package com.ltv.xiangqiplugin.views;

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;

import javax.swing.JApplet;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import com.ltv.xiangqiplugin.controllers.BoardViewControl;
import com.ltv.xiangqiplugin.controllers.GameActionControl;
import com.ltv.xiangqiplugin.controllers.MoveListControl;
import com.ltv.xiangqiplugin.controllers.OptionControl;
import com.ltv.xiangqiplugin.models.BoardSizeEnum;
import com.ltv.xiangqiplugin.models.Game;
import com.ltv.xiangqiplugin.models.Languages;
import com.ltv.xiangqiplugin.models.Messages;
import com.ltv.xiangqiplugin.models.MoveStack;
import com.ltv.xiangqiplugin.models.PositionStack;
import com.ltv.xiangqiplugin.models.Themes;
import com.ltv.xiangqiplugin.utils.MoveUtils;

@SuppressWarnings("serial")
public class ChessApp extends JApplet {
	private static Vector<String> bufferedMoves;
	private static Vector<String> bufferedVnMoves;
	private static Vector<String> bufferedPositions;
	private static int bufferedIndex;

	private String initPosition;
	private String moveList;
	private Integer startIndex;
	private Languages language;
	private Themes theme;

	private boolean started;

	private boolean isActive;
	private String boardSize;


	private BoardViewControl boardViewControl;
	private BoardView boardView;

	private GameActionControl gameActionControl;
	private GameActionView gameActionView;

	private MoveListControl moveListControl;
	private MoveStackView moveStackView;

	private MoveStack moveStack;
	private PositionStack positionStack;

	private Game game;

	private OptionView optionView;
	private OptionControl optionControl;
	
//	private JSObject win;
	
	private HtmlView htmlView;
	
	// If this applet is added to a standalone app
	private boolean standaloneApp = false;
	
	public boolean isStandaloneApp() {
		return standaloneApp;
	}

	public void setStandaloneApp(boolean standaloneApp) {
		this.standaloneApp = standaloneApp;
	}
	
	public ChessApp() {
	}

	public BoardViewControl getBoardViewControl() {
		return boardViewControl;
	}

	public BoardView getBoardView() {
		return boardView;
	}

	public GameActionControl getGameActionControl() {
		return gameActionControl;
	}

	public GameActionView getGameActionView() {
		return gameActionView;
	}

	public MoveListControl getMoveListControl() {
		return moveListControl;
	}

	public MoveStackView getMoveStackView() {
		return moveStackView;
	}

	public MoveStack getMoveStack() {
		return moveStack;
	}

	public PositionStack getPositionStack() {
		return positionStack;
	}

	public OptionView getOptionView() {
		return optionView;
	}

	public OptionControl getOptionControl() {
		return optionControl;
	}
	
	public HtmlView getHtmlView() {
		return htmlView;
	}

	@Override
	public void init() {
//		win = JSObject.getWindow(this);
		game = new Game();

		moveStack = new MoveStack();
		positionStack = new PositionStack();

		boardViewControl = new BoardViewControl(this);
		boardView = new BoardView(this);
		boardView.setGame(game);

		gameActionControl = new GameActionControl(this);
		gameActionView = new GameActionView(this);

		moveListControl = new MoveListControl(this);
		moveStackView = new MoveStackView(this);

		optionControl = new OptionControl(this);

		moveStack.addObserver(moveStackView);
		positionStack.addObserver(boardView);

		optionView = new OptionView(this);

		htmlView = new HtmlView();
		
		Messages.getInstance().addObserver(boardView);
		Messages.getInstance().addObserver(gameActionView);
		Messages.getInstance().addObserver(moveStackView);
		Messages.getInstance().addObserver(optionView);
		
		initParameters();
		JMenuBar myMenu = new JMenuBar();
		JMenu main = new JMenu(Messages.getInstance().getProperty("menu.help"));

		JMenuItem item = new JMenuItem(Messages.getInstance().getProperty("menu.help.about") + " " + "CCViewer");
		main.add(item);
		item.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				AboutView.getInstance().showContent("CCViewer");
			}
		});
		
		myMenu.add(main);
		this.setJMenuBar(myMenu);
	}

	private void initParameters() {
		language = Languages.EN;
		String languageParam = this.getParameter("language");
		if (languageParam != null && languageParam.trim().equalsIgnoreCase(Languages.VI.toString())) {
			language = Languages.VI;
		}
		
		theme = Themes.THEME_1;
		String themeParam = this.getParameter("theme");
		if (themeParam != null && themeParam.trim().equalsIgnoreCase(Integer.toString(Themes.THEME_2.getValue()))) {
			theme = Themes.THEME_2;
		}

		try {
			if (!isStandaloneApp()) {
				Messages.getInstance().setLang(language);
			}
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		
		if (!isStandaloneApp()) {
			Messages.getInstance().setTheme(theme);
		}

		initPosition = this.getParameter("initPosition");
		moveList = this.getParameter("moveList");

		startIndex = 0;
		try {
			startIndex = Integer.parseInt(this.getParameter("startIndex"));
		} catch (Exception e) {
			startIndex = 0;
		}

		isActive = true;
		String isActiveStr = this.getParameter("isActive");

		if (isActiveStr != null && isActiveStr.trim().equalsIgnoreCase("false")) {
			isActive = false;
		}

		if (boardSize == null || boardSize.trim().equals("")) {
			boardSize = this.getParameter("boardSize");
		}
		if (boardSize == null || boardSize.trim().equals("")) {
			boardSize = BoardSizeEnum.MEDIUM.toString();
		}
	}

	private void createGUI() throws Exception {
		JPanel mainPanel = new JPanel();
		mainPanel.setLayout(new GridBagLayout());

		if (initPosition != null && !initPosition.trim().equals("")) {
			
			game = new Game();
			try {
				game.setPosition(initPosition);
			} catch (Exception e) {
				game = new Game();
			}
			getBoardView().setGame(game);
			getBoardView().clearHighlights();
			getBoardView().clearLastMoves();
			getBoardViewControl().setOriginPanel(null);
			
			getPositionStack().getPositions().clear();
			getMoveStack().getMoves().clear();
			getMoveStack().getVnMoves().clear();
			
			getPositionStack().getPositions().add(game.getPosition());
			getMoveStack().getMoves().add("start");
			getMoveStack().getVnMoves().add("start");
			
			getPositionStack().setIndex(0);
			getMoveStack().setIndex(0);
			
			getPositionStack().notifyObservers();
			getMoveStack().notifyObservers(true);
		}

		if (!isStandaloneApp()) {
			if (boardSize.equalsIgnoreCase(BoardSizeEnum.SMALL.toString())) {
				Messages.getInstance().setBoardSize(BoardSizeEnum.SMALL);
			} else if (boardSize.equalsIgnoreCase(BoardSizeEnum.MEDIUM.toString())) {
				Messages.getInstance().setBoardSize(BoardSizeEnum.MEDIUM);
			} else if (boardSize.equalsIgnoreCase(BoardSizeEnum.LARGE.toString())) {
				Messages.getInstance().setBoardSize(BoardSizeEnum.LARGE);
			} else {
				Messages.getInstance().setBoardSize(BoardSizeEnum.MEDIUM);
			}
		}
		
		Messages.getInstance().notifyObservers();

		if (moveList != null && !moveList.trim().equals("")) {
			String moves[] = moveList.toLowerCase().split("\\+");

			try {
				for (String move : moves) {
					move = MoveUtils.getPGNMove(move);
					String vnMove = MoveUtils.getVnMove(move, game);
					if (game.move(move, false)) {
						positionStack.addPostion(game.getPosition());
						moveStack.addMove(move);
						moveStack.addVnMove(vnMove);
					} else {
						throw new Exception("Invalid moveList");
					}
				}
			} catch (Exception e) {
				game = new Game();
				if (initPosition != null && !initPosition.trim().equals("")) {
					try {
						game.setPosition(initPosition);
					} catch (Exception e1) {
						// Do nothing
					}
				}
				
				positionStack.getPositions().clear();
				moveStack.getMoves().clear();
				moveStack.getVnMoves().clear();
				
				positionStack.addPostion(game.getPosition());
				moveStack.addMove("start");
				moveStack.addVnMove("start");
			}
			
			moveStack.notifyObservers(true);
		}

		positionStack.notifyObservers();

		if (startIndex > 0 && startIndex < positionStack.getPositions().size()) {
			startIndex = positionStack.getPositions().size() - startIndex - 1;

			positionStack.setIndex(startIndex);
			moveStack.setIndex(startIndex);

			positionStack.notifyObservers();
			moveStack.notifyObservers(false);
		} else {
			positionStack.first();
			moveStack.first();
		}

		bufferedPositions = new Vector<String>();
		for (String position : positionStack.getPositions()) {
			bufferedPositions.add(position);
		}

		bufferedMoves = new Vector<String>();
		for (String move : moveStack.getMoves()) {
			bufferedMoves.add(move);
		}

		bufferedVnMoves = new Vector<String>();
		for (String vnMove : moveStack.getVnMoves()) {
			bufferedVnMoves.add(vnMove);
		}

		bufferedIndex = 0;

		GridBagConstraints constrs = new GridBagConstraints();

		constrs.fill = GridBagConstraints.BOTH;
		constrs.gridx = 0;
		constrs.gridy = 0;
		mainPanel.add(boardView, constrs);

		constrs.fill = GridBagConstraints.BOTH;
		constrs.gridwidth = 2;
		constrs.gridx = 0;
		constrs.gridy = 1;
		mainPanel.add(gameActionView, constrs);

		if (!isActive) {
			boardView.removeMouseListener();
			gameActionView.changeToInactiveMode();
		}


		constrs.fill = GridBagConstraints.BOTH;
		constrs.weightx = 1.0;
		constrs.gridx = 1;
		constrs.gridy = 0;
		mainPanel.add(moveStackView, constrs);

		this.getContentPane().setLayout(new BorderLayout());
		this.getContentPane().add(mainPanel, BorderLayout.NORTH);
	}



	@Override
	public void start() {
		if (!started) {
			//Execute a job on the event-dispatching thread; creating this applet's GUI.
			try {
				SwingUtilities.invokeAndWait(new Runnable() {
					public void run() {
						try {
							createGUI();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				});
			} catch (Exception e) { 
				e.printStackTrace();
			}
			started = true;
		}
	}



	@Override
	public void stop() {
		started = false;
	}

	public static Vector<String> getBufferedMoves() {
		Vector<String> ret = new Vector<String>();
		for (String move : bufferedMoves) {
			ret.add(move);
		}

		return ret;
	}

	public static Vector<String> getBufferedVnMoves() {
		Vector<String> ret = new Vector<String>();
		for (String vnMove : bufferedVnMoves) {
			ret.add(vnMove);
		}

		return ret;
	}

	public static Vector<String> getBufferedPositions() {
		Vector<String> ret = new Vector<String>();
		for (String position : bufferedPositions) {
			ret.add(position);
		}

		return ret;

	}

	public static int getBufferedIndex() {
		return bufferedIndex;
	}

	public static void setBufferedIndex(int bufferedIndex) {
		ChessApp.bufferedIndex = bufferedIndex;
	}

//	public JSObject getWin() {
//		return win;
//	}
	
}
